@file:Suppress("unused")
package ai.platon.cdt.kt.protocol.commands

import ai.platon.cdt.kt.protocol.events.input.DragIntercepted
import ai.platon.cdt.kt.protocol.support.annotations.EventName
import ai.platon.cdt.kt.protocol.support.annotations.Experimental
import ai.platon.cdt.kt.protocol.support.annotations.Optional
import ai.platon.cdt.kt.protocol.support.annotations.ParamName
import ai.platon.cdt.kt.protocol.support.types.EventHandler
import ai.platon.cdt.kt.protocol.support.types.EventListener
import ai.platon.cdt.kt.protocol.types.input.DispatchDragEventType
import ai.platon.cdt.kt.protocol.types.input.DispatchKeyEventType
import ai.platon.cdt.kt.protocol.types.input.DispatchMouseEventPointerType
import ai.platon.cdt.kt.protocol.types.input.DispatchMouseEventType
import ai.platon.cdt.kt.protocol.types.input.DispatchTouchEventType
import ai.platon.cdt.kt.protocol.types.input.DragData
import ai.platon.cdt.kt.protocol.types.input.EmulateTouchFromMouseEventType
import ai.platon.cdt.kt.protocol.types.input.GestureSourceType
import ai.platon.cdt.kt.protocol.types.input.MouseButton
import ai.platon.cdt.kt.protocol.types.input.TouchPoint
import kotlin.Boolean
import kotlin.Double
import kotlin.Int
import kotlin.String
import kotlin.Unit
import kotlin.collections.List

interface Input {
  /**
   * Dispatches a drag event into the page.
   * @param type Type of the drag event.
   * @param x X coordinate of the event relative to the main frame's viewport in CSS pixels.
   * @param y Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to
   * the top of the viewport and Y increases as it proceeds towards the bottom of the viewport.
   * @param data
   * @param modifiers Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8
   * (default: 0).
   */
  @Experimental
  suspend fun dispatchDragEvent(
    @ParamName("type") type: DispatchDragEventType,
    @ParamName("x") x: Double,
    @ParamName("y") y: Double,
    @ParamName("data") `data`: DragData,
    @ParamName("modifiers") @Optional modifiers: Int? = null,
  )

  @Experimental
  suspend fun dispatchDragEvent(
    @ParamName("type") type: DispatchDragEventType,
    @ParamName("x") x: Double,
    @ParamName("y") y: Double,
    @ParamName("data") `data`: DragData,
  ) {
    return dispatchDragEvent(type, x, y, `data`, null)
  }

  /**
   * Dispatches a key event to the page.
   * @param type Type of the key event.
   * @param modifiers Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8
   * (default: 0).
   * @param timestamp Time at which the event occurred.
   * @param text Text as generated by processing a virtual key code with a keyboard layout. Not needed for
   * for `keyUp` and `rawKeyDown` events (default: "")
   * @param unmodifiedText Text that would have been generated by the keyboard if no modifiers were pressed (except for
   * shift). Useful for shortcut (accelerator) key handling (default: "").
   * @param keyIdentifier Unique key identifier (e.g., 'U+0041') (default: "").
   * @param code Unique DOM defined string value for each physical key (e.g., 'KeyA') (default: "").
   * @param key Unique DOM defined string value describing the meaning of the key in the context of active
   * modifiers, keyboard layout, etc (e.g., 'AltGr') (default: "").
   * @param windowsVirtualKeyCode Windows virtual key code (default: 0).
   * @param nativeVirtualKeyCode Native virtual key code (default: 0).
   * @param autoRepeat Whether the event was generated from auto repeat (default: false).
   * @param isKeypad Whether the event was generated from the keypad (default: false).
   * @param isSystemKey Whether the event was a system key event (default: false).
   * @param location Whether the event was from the left or right side of the keyboard. 1=Left, 2=Right (default:
   * 0).
   * @param commands Editing commands to send with the key event (e.g., 'selectAll') (default: []).
   * These are related to but not equal the command names used in `document.execCommand` and NSStandardKeyBindingResponding.
   * See https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/core/editing/commands/editor_command_names.h for valid command names.
   */
  suspend fun dispatchKeyEvent(
    @ParamName("type") type: DispatchKeyEventType,
    @ParamName("modifiers") @Optional modifiers: Int? = null,
    @ParamName("timestamp") @Optional timestamp: Double? = null,
    @ParamName("text") @Optional text: String? = null,
    @ParamName("unmodifiedText") @Optional unmodifiedText: String? = null,
    @ParamName("keyIdentifier") @Optional keyIdentifier: String? = null,
    @ParamName("code") @Optional code: String? = null,
    @ParamName("key") @Optional key: String? = null,
    @ParamName("windowsVirtualKeyCode") @Optional windowsVirtualKeyCode: Int? = null,
    @ParamName("nativeVirtualKeyCode") @Optional nativeVirtualKeyCode: Int? = null,
    @ParamName("autoRepeat") @Optional autoRepeat: Boolean? = null,
    @ParamName("isKeypad") @Optional isKeypad: Boolean? = null,
    @ParamName("isSystemKey") @Optional isSystemKey: Boolean? = null,
    @ParamName("location") @Optional location: Int? = null,
    @ParamName("commands") @Optional @Experimental commands: List<String>? = null,
  )

  suspend fun dispatchKeyEvent(@ParamName("type") type: DispatchKeyEventType) {
    return dispatchKeyEvent(type, null, null, null, null, null, null, null, null, null, null, null, null, null, null)
  }

  /**
   * This method emulates inserting text that doesn't come from a key press,
   * for example an emoji keyboard or an IME.
   * @param text The text to insert.
   */
  @Experimental
  suspend fun insertText(@ParamName("text") text: String)

  /**
   * Dispatches a mouse event to the page.
   * @param type Type of the mouse event.
   * @param x X coordinate of the event relative to the main frame's viewport in CSS pixels.
   * @param y Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to
   * the top of the viewport and Y increases as it proceeds towards the bottom of the viewport.
   * @param modifiers Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8
   * (default: 0).
   * @param timestamp Time at which the event occurred.
   * @param button Mouse button (default: "none").
   * @param buttons A number indicating which buttons are pressed on the mouse when a mouse event is triggered.
   * Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0.
   * @param clickCount Number of times the mouse button was clicked (default: 0).
   * @param force The normalized pressure, which has a range of [0,1] (default: 0).
   * @param tangentialPressure The normalized tangential pressure, which has a range of [-1,1] (default: 0).
   * @param tiltX The plane angle between the Y-Z plane and the plane containing both the stylus axis and the Y axis, in degrees of the range [-90,90], a positive tiltX is to the right (default: 0).
   * @param tiltY The plane angle between the X-Z plane and the plane containing both the stylus axis and the X axis, in degrees of the range [-90,90], a positive tiltY is towards the user (default: 0).
   * @param twist The clockwise rotation of a pen stylus around its own major axis, in degrees in the range [0,359] (default: 0).
   * @param deltaX X delta in CSS pixels for mouse wheel event (default: 0).
   * @param deltaY Y delta in CSS pixels for mouse wheel event (default: 0).
   * @param pointerType Pointer type (default: "mouse").
   */
  suspend fun dispatchMouseEvent(
    @ParamName("type") type: DispatchMouseEventType,
    @ParamName("x") x: Double,
    @ParamName("y") y: Double,
    @ParamName("modifiers") @Optional modifiers: Int? = null,
    @ParamName("timestamp") @Optional timestamp: Double? = null,
    @ParamName("button") @Optional button: MouseButton? = null,
    @ParamName("buttons") @Optional buttons: Int? = null,
    @ParamName("clickCount") @Optional clickCount: Int? = null,
    @ParamName("force") @Optional @Experimental force: Double? = null,
    @ParamName("tangentialPressure") @Optional @Experimental tangentialPressure: Double? = null,
    @ParamName("tiltX") @Optional @Experimental tiltX: Int? = null,
    @ParamName("tiltY") @Optional @Experimental tiltY: Int? = null,
    @ParamName("twist") @Optional @Experimental twist: Int? = null,
    @ParamName("deltaX") @Optional deltaX: Double? = null,
    @ParamName("deltaY") @Optional deltaY: Double? = null,
    @ParamName("pointerType") @Optional pointerType: DispatchMouseEventPointerType? = null,
  )

  suspend fun dispatchMouseEvent(
    @ParamName("type") type: DispatchMouseEventType,
    @ParamName("x") x: Double,
    @ParamName("y") y: Double,
  ) {
    return dispatchMouseEvent(type, x, y, null, null, null, null, null, null, null, null, null, null, null, null, null)
  }

  /**
   * Dispatches a touch event to the page.
   * @param type Type of the touch event. TouchEnd and TouchCancel must not contain any touch points, while
   * TouchStart and TouchMove must contains at least one.
   * @param touchPoints Active touch points on the touch device. One event per any changed point (compared to
   * previous touch event in a sequence) is generated, emulating pressing/moving/releasing points
   * one by one.
   * @param modifiers Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8
   * (default: 0).
   * @param timestamp Time at which the event occurred.
   */
  suspend fun dispatchTouchEvent(
    @ParamName("type") type: DispatchTouchEventType,
    @ParamName("touchPoints") touchPoints: List<TouchPoint>,
    @ParamName("modifiers") @Optional modifiers: Int? = null,
    @ParamName("timestamp") @Optional timestamp: Double? = null,
  )

  suspend fun dispatchTouchEvent(@ParamName("type") type: DispatchTouchEventType, @ParamName("touchPoints") touchPoints: List<TouchPoint>) {
    return dispatchTouchEvent(type, touchPoints, null, null)
  }

  /**
   * Emulates touch event from the mouse event parameters.
   * @param type Type of the mouse event.
   * @param x X coordinate of the mouse pointer in DIP.
   * @param y Y coordinate of the mouse pointer in DIP.
   * @param button Mouse button. Only "none", "left", "right" are supported.
   * @param timestamp Time at which the event occurred (default: current time).
   * @param deltaX X delta in DIP for mouse wheel event (default: 0).
   * @param deltaY Y delta in DIP for mouse wheel event (default: 0).
   * @param modifiers Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8
   * (default: 0).
   * @param clickCount Number of times the mouse button was clicked (default: 0).
   */
  @Experimental
  suspend fun emulateTouchFromMouseEvent(
    @ParamName("type") type: EmulateTouchFromMouseEventType,
    @ParamName("x") x: Int,
    @ParamName("y") y: Int,
    @ParamName("button") button: MouseButton,
    @ParamName("timestamp") @Optional timestamp: Double? = null,
    @ParamName("deltaX") @Optional deltaX: Double? = null,
    @ParamName("deltaY") @Optional deltaY: Double? = null,
    @ParamName("modifiers") @Optional modifiers: Int? = null,
    @ParamName("clickCount") @Optional clickCount: Int? = null,
  )

  @Experimental
  suspend fun emulateTouchFromMouseEvent(
    @ParamName("type") type: EmulateTouchFromMouseEventType,
    @ParamName("x") x: Int,
    @ParamName("y") y: Int,
    @ParamName("button") button: MouseButton,
  ) {
    return emulateTouchFromMouseEvent(type, x, y, button, null, null, null, null, null)
  }

  /**
   * Ignores input events (useful while auditing page).
   * @param ignore Ignores input events processing when set to true.
   */
  suspend fun setIgnoreInputEvents(@ParamName("ignore") ignore: Boolean)

  /**
   * Prevents default drag and drop behavior and instead emits `Input.dragIntercepted` events.
   * Drag and drop behavior can be directly controlled via `Input.dispatchDragEvent`.
   * @param enabled
   */
  @Experimental
  suspend fun setInterceptDrags(@ParamName("enabled") enabled: Boolean)

  /**
   * Synthesizes a pinch gesture over a time period by issuing appropriate touch events.
   * @param x X coordinate of the start of the gesture in CSS pixels.
   * @param y Y coordinate of the start of the gesture in CSS pixels.
   * @param scaleFactor Relative scale factor after zooming (>1.0 zooms in, <1.0 zooms out).
   * @param relativeSpeed Relative pointer speed in pixels per second (default: 800).
   * @param gestureSourceType Which type of input events to be generated (default: 'default', which queries the platform
   * for the preferred input type).
   */
  @Experimental
  suspend fun synthesizePinchGesture(
    @ParamName("x") x: Double,
    @ParamName("y") y: Double,
    @ParamName("scaleFactor") scaleFactor: Double,
    @ParamName("relativeSpeed") @Optional relativeSpeed: Int? = null,
    @ParamName("gestureSourceType") @Optional gestureSourceType: GestureSourceType? = null,
  )

  @Experimental
  suspend fun synthesizePinchGesture(
    @ParamName("x") x: Double,
    @ParamName("y") y: Double,
    @ParamName("scaleFactor") scaleFactor: Double,
  ) {
    return synthesizePinchGesture(x, y, scaleFactor, null, null)
  }

  /**
   * Synthesizes a scroll gesture over a time period by issuing appropriate touch events.
   * @param x X coordinate of the start of the gesture in CSS pixels.
   * @param y Y coordinate of the start of the gesture in CSS pixels.
   * @param xDistance The distance to scroll along the X axis (positive to scroll left).
   * @param yDistance The distance to scroll along the Y axis (positive to scroll up).
   * @param xOverscroll The number of additional pixels to scroll back along the X axis, in addition to the given
   * distance.
   * @param yOverscroll The number of additional pixels to scroll back along the Y axis, in addition to the given
   * distance.
   * @param preventFling Prevent fling (default: true).
   * @param speed Swipe speed in pixels per second (default: 800).
   * @param gestureSourceType Which type of input events to be generated (default: 'default', which queries the platform
   * for the preferred input type).
   * @param repeatCount The number of times to repeat the gesture (default: 0).
   * @param repeatDelayMs The number of milliseconds delay between each repeat. (default: 250).
   * @param interactionMarkerName The name of the interaction markers to generate, if not empty (default: "").
   */
  @Experimental
  suspend fun synthesizeScrollGesture(
    @ParamName("x") x: Double,
    @ParamName("y") y: Double,
    @ParamName("xDistance") @Optional xDistance: Double? = null,
    @ParamName("yDistance") @Optional yDistance: Double? = null,
    @ParamName("xOverscroll") @Optional xOverscroll: Double? = null,
    @ParamName("yOverscroll") @Optional yOverscroll: Double? = null,
    @ParamName("preventFling") @Optional preventFling: Boolean? = null,
    @ParamName("speed") @Optional speed: Int? = null,
    @ParamName("gestureSourceType") @Optional gestureSourceType: GestureSourceType? = null,
    @ParamName("repeatCount") @Optional repeatCount: Int? = null,
    @ParamName("repeatDelayMs") @Optional repeatDelayMs: Int? = null,
    @ParamName("interactionMarkerName") @Optional interactionMarkerName: String? = null,
  )

  @Experimental
  suspend fun synthesizeScrollGesture(@ParamName("x") x: Double, @ParamName("y") y: Double) {
    return synthesizeScrollGesture(x, y, null, null, null, null, null, null, null, null, null, null)
  }

  /**
   * Synthesizes a tap gesture over a time period by issuing appropriate touch events.
   * @param x X coordinate of the start of the gesture in CSS pixels.
   * @param y Y coordinate of the start of the gesture in CSS pixels.
   * @param duration Duration between touchdown and touchup events in ms (default: 50).
   * @param tapCount Number of times to perform the tap (e.g. 2 for double tap, default: 1).
   * @param gestureSourceType Which type of input events to be generated (default: 'default', which queries the platform
   * for the preferred input type).
   */
  @Experimental
  suspend fun synthesizeTapGesture(
    @ParamName("x") x: Double,
    @ParamName("y") y: Double,
    @ParamName("duration") @Optional duration: Int? = null,
    @ParamName("tapCount") @Optional tapCount: Int? = null,
    @ParamName("gestureSourceType") @Optional gestureSourceType: GestureSourceType? = null,
  )

  @Experimental
  suspend fun synthesizeTapGesture(@ParamName("x") x: Double, @ParamName("y") y: Double) {
    return synthesizeTapGesture(x, y, null, null, null)
  }

  @EventName("dragIntercepted")
  @Experimental
  fun onDragIntercepted(eventListener: EventHandler<DragIntercepted>): EventListener

  @EventName("dragIntercepted")
  @Experimental
  fun onDragIntercepted(eventListener: suspend (DragIntercepted) -> Unit): EventListener
}
